home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / xlib / iobounce.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  12KB  |  352 lines

  1. /*
  2.  * Copyright (c) 1993-94, Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  21.  */
  22. /* 
  23.  *  iobounce:  an openGL-Xlib 2-D animation program.
  24.  *
  25.  *           iobounce is the openGL "after" version of the IrisGL
  26.  *           "before" program, ~4Dgifts/examples/grafix/iobounce.c.
  27.  *
  28.  *                RIGHTMOUSE  stops ball
  29.  *                MIDDLEMOUSE increases y velocity
  30.  *                LEFTMOUSE   increases x velocity
  31.  *
  32.  *   iobounce is a "pool ball" that "bounces" around a 2-d "surface". 
  33.  *
  34.  *                                   ratmandu -- ported to openGL, april '93
  35.  */
  36.  
  37. #include <GL/glx.h>
  38. #include <GL/gl.h>
  39. #include <GL/glu.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <X11/keysym.h>
  43. #include <X11/Xlib.h>
  44. #include <X11/Xutil.h>
  45.  
  46. #define XMIN 100
  47. #define YMIN 100
  48. #define XMAX 900
  49. #define YMAX 700
  50.  
  51. #define BLACK           0
  52. #define YELLOW          3
  53.  
  54. #define LEFTMOUSE       3
  55. #define MIDDLEMOUSE     2
  56. #define RIGHTMOUSE      1
  57.  
  58. #define TRUE            1
  59. #define FALSE           0
  60.  
  61. long xmaxscrn, ymaxscrn;         /* maximum size of screen in x and y       */
  62.  
  63. Display *dpy;                                    /* The X server connection */
  64. Atom del_atom;                                   /* WM_DELETE_WINDOW atom   */
  65. Window glwin;                                    /* handle to the GL window */
  66. XEvent event;
  67.  
  68. static void openwindow(char *);
  69. static void drawball(void);
  70. static void clean_exit(void);
  71.  
  72. long xvelocity = 0, yvelocity = 0;
  73.  
  74. main(int argc, char *argv[])
  75. {
  76.     int myExpose, myConfigure,
  77.     myButtRelease, myKeyPress,
  78.         myButtonNumber;                         /* store which events occur */
  79.     long xsize, ysize;
  80.  
  81.  
  82.  
  83.     myExpose = myConfigure = myButtRelease = myKeyPress = FALSE;
  84.  
  85.     openwindow(argv[0]);
  86.  
  87.     while (TRUE) {
  88.  
  89.         KeySym keysym;
  90.         char buf[4];
  91.  
  92.     /* this "do while" loop does the `get events' half of the "get events,
  93.      *  process events" action of the infinite while.  this is to ensure
  94.      *  the event queue is always drained before the events that have come
  95.      *  in are processed.
  96.      */
  97.         while (XEventsQueued(dpy,QueuedAfterReading)) { 
  98.                                    /* XEventsQueued(dpy,QueuedAfterReading) is 
  99.                     * like qtest()--it only tells you if 
  100.                     * there're any events presently in the 
  101.                     * queue.  it does not disturb the event
  102.                     * queue's contents in any way.
  103.                                     */
  104.  
  105.             XNextEvent(dpy, &event);
  106.             switch (event.type) {
  107.  
  108.             /* "Expose" events are sort of like "REDRAW" in gl-speak in
  109.              *  terms of when a window becomes visible, or a previously
  110.              *  invisible part becomes visible.
  111.              */
  112.                 case Expose:                        /* Exposures */
  113.                     myExpose = TRUE;
  114.                     break;
  115.  
  116.             /* "ConfigNotify" events are like "REDRAW" in terms of changes
  117.              *   to a window's size or position.
  118.              */
  119.                 case ConfigureNotify:                /* Resize GL manually */
  120.                     xsize = event.xconfigure.width;
  121.                     ysize = event.xconfigure.height;
  122.                     myConfigure = TRUE;
  123.                     break;
  124.  
  125.             /* Wait for "ButtonRelease" events so the queue doesn't fill up
  126.              *  the way it wud if the user sits on ButtonPresss.
  127.              */
  128.                 case ButtonRelease:
  129.                     if (event.xbutton.button == Button1) {  
  130.                         myButtonNumber = LEFTMOUSE;        
  131.                         myButtRelease = TRUE;             
  132.                     } else if (event.xbutton.button == Button2) {
  133.                         myButtonNumber = MIDDLEMOUSE;
  134.                         myButtRelease = TRUE;      
  135.                     } else if (event.xbutton.button == Button3) {
  136.                         myButtonNumber = RIGHTMOUSE;
  137.                         myButtRelease = TRUE; 
  138.                     }                            /* twirl the green sphere */
  139.                     break;
  140.  
  141.             /* "ClientMessage" is generated if the WM itself is being
  142.              *  gunned down and sends an exit signal to any running prog.
  143.              */
  144.                 case ClientMessage:
  145.                     if (event.xclient.data.l[0] == del_atom)
  146.                         clean_exit();
  147.                     break;
  148.  
  149.  
  150.             /* "KeyPress" events are those that would be generated before
  151.              *   whenever queueing up any KEYBD key via qdevice.
  152.              */
  153.                 case KeyPress:
  154.                    /* save out which unmodified key (i.e. the  key was
  155.                     *  not modified w/something like "Shift", "Ctrl",
  156.                     *  or "Alt") got pressed for use below.
  157.                     */
  158.                     XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
  159.                     myKeyPress = TRUE;
  160.                     break;
  161.  
  162.             }  /* end switch (event.type) */
  163.         }  /* end while (XEventsQueued(dpy,QueuedAfterReading)) { */
  164.  
  165.     /* On an "Expose" event, redraw the affected pop'd or de-iconized window
  166.      */
  167.         if (myExpose) {
  168.             drawball();                               /* draw the GL stuff */
  169.             myExpose = FALSE;               /* reset flag--queue now empty */
  170.         }
  171.  
  172.  
  173.     /* On a "ConfigureNotify" event, the GL window has either been moved or
  174.      *  resized.  Respond accordingly and then redraw its contents.
  175.      */
  176.         if (myConfigure) {
  177.             glViewport(0, 0, xsize, ysize);
  178.         glLoadIdentity();
  179.             gluOrtho2D(XMIN-0.5, XMAX+0.5, YMIN-0.5, YMAX+0.5);
  180.             drawball();                               /* draw the GL stuff */
  181.             myConfigure = FALSE;            /* reset flag--queue now empty */
  182.         }
  183.  
  184.     /* On a "ButtonRelease" event, myButtonNumber stores which mouse button
  185.      * was pressed/released and then we update x/yvelocity accordingly
  186.      */
  187.         if (myButtRelease) {
  188.             if (myButtonNumber == LEFTMOUSE) {       /* increase xvelocity */
  189.                 if (xvelocity >= 0)
  190.                     xvelocity += 3;
  191.                 else
  192.                     xvelocity -= 3;
  193.             } else if (myButtonNumber == MIDDLEMOUSE) {/*increase yvelocity*/
  194.                 if (yvelocity >= 0)
  195.                     yvelocity += 3;
  196.                 else
  197.                     yvelocity -= 3;
  198.             } else if (myButtonNumber == RIGHTMOUSE) {        /* stop ball */
  199.                 xvelocity = yvelocity = 0;
  200.             } else {
  201.                 fprintf(stderr,"ERROR: %s thinks mouse button # ");
  202.         fprintf(stderr,"%d was pressed(?)\n",argv[0],myButtonNumber);
  203.         }
  204.             drawball();
  205.             myButtRelease = FALSE;
  206.         }
  207.  
  208.         /* On a keypress of Esc key, exit program.
  209.          */
  210.         if (myKeyPress) {
  211.             if (keysym == XK_Escape)
  212.                 clean_exit();
  213.         }
  214.         drawball();
  215.  
  216.     }
  217. }
  218.  
  219.  
  220. static int attributeList[] = { GLX_DOUBLEBUFFER, 
  221.                                None };
  222. GLUquadricObj *qobj; 
  223.  
  224. static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
  225.     return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
  226. }
  227.  
  228. static void 
  229. openwindow(char *progname) 
  230. {
  231.     int scrnnum;                               /* X screen number            */
  232.     int xorig, yorig;                          /* window (upper-left) origin */
  233.     XVisualInfo *vi;
  234.     GLXContext cx;
  235.     Colormap cmap;
  236.     XSizeHints Winhints;                          /* used to fix window size */
  237.     XSetWindowAttributes swa;
  238.     XColor colorstruct;
  239.  
  240.  
  241.     /* Connect to the X server and get screen info */
  242.     if ((dpy = XOpenDisplay(NULL)) == NULL) {
  243.         fprintf(stderr, "%s: cannot connect to X server %s\n",
  244.                                  progname, XDisplayName(NULL));
  245.         exit(1);
  246.     }
  247.     scrnnum = DefaultScreen(dpy);
  248.     ymaxscrn = DisplayHeight(dpy, scrnnum);
  249.     xmaxscrn = DisplayWidth(dpy, scrnnum);
  250.  
  251.     /* get an appropriate visual */
  252.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
  253.     if (vi == NULL) {
  254.     printf("Couldn't get visual.\n");
  255.     exit(0);
  256.     }
  257.  
  258.     /* create a GLX context */
  259.     cx = glXCreateContext(dpy, vi, None, GL_TRUE);
  260.     if (cx == NULL) {
  261.     printf("Couldn't get context.\n");
  262.     exit(0);
  263.     }
  264.  
  265.     /* create a colormap */
  266.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  267.                            vi->visual, AllocAll);
  268.  
  269.     XSync(dpy, 0);
  270.     /* create a window */
  271.     swa.colormap = cmap;
  272.     swa.border_pixel = 0;
  273.  
  274.     /* express interest in certain events */
  275.     swa.event_mask = StructureNotifyMask | KeyPressMask | ButtonPressMask |
  276.                ButtonReleaseMask | ExposureMask;
  277.     glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 
  278.                           10, 10, 300, 300,
  279.                           0, vi->depth, InputOutput, vi->visual,
  280.                           CWBorderPixel|CWColormap|CWEventMask, &swa);
  281.  
  282.     XMapWindow(dpy, glwin);
  283.     XIfEvent(dpy, &event, WaitForNotify, (char*)glwin);
  284.  
  285.     /* connect the context to the window */
  286.     glXMakeCurrent(dpy, glwin, cx);
  287.  
  288.    /* express interest in WM killing this app */
  289.     if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", True)) != None)
  290.         XSetWMProtocols(dpy, glwin, &del_atom, 1);
  291.  
  292.     colorstruct.pixel = BLACK;    
  293.     colorstruct.red   = 0;
  294.     colorstruct.green = 0;
  295.     colorstruct.blue  = 0;
  296.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  297.     XStoreColor(dpy, cmap, &colorstruct);
  298.     colorstruct.pixel = YELLOW;
  299.     colorstruct.red   = 65535;
  300.     colorstruct.green = 65535;
  301.     colorstruct.blue  = 0;
  302.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  303.     XStoreColor(dpy, cmap, &colorstruct);
  304.  
  305.     glLoadIdentity();
  306.     gluOrtho2D(XMIN - 0.5,  XMAX + 0.5,  YMIN - 0.5,  YMAX + 0.5);
  307.  
  308.     /* clear the buffer */
  309.     glClearIndex((GLfloat)BLACK);
  310.     qobj = gluNewQuadric(); 
  311.     gluQuadricDrawStyle(qobj,GLU_FILL);
  312.     glFlush();
  313. }
  314.  
  315.  
  316. static void 
  317. drawball(void) 
  318. {
  319.     static int xpos = 500, ypos = 500;
  320.     GLdouble radius = 14.0;
  321.  
  322.  
  323.     glClear(GL_COLOR_BUFFER_BIT);
  324.     xpos += xvelocity;
  325.     ypos += yvelocity;
  326.     if (xpos > XMAX - radius || xpos < XMIN + radius) {
  327.         xpos -= xvelocity;
  328.         xvelocity = -xvelocity;
  329.     }
  330.     if (ypos > YMAX - radius || ypos < YMIN + radius) {
  331.         ypos -= yvelocity;
  332.         yvelocity = -yvelocity;
  333.     }
  334.     glIndexi(YELLOW);
  335.     glPushMatrix(); 
  336.     glTranslatef(xpos,  ypos, 0.); 
  337.     gluDisk( qobj, 0., radius, 10, 1); 
  338.     glPopMatrix(); 
  339.     glXSwapBuffers(dpy, glwin);
  340. }
  341.  
  342.  
  343. /*  clean_exit  --  Clean up before exiting
  344.  */
  345. static void 
  346. clean_exit(void)
  347. {
  348.     gluDeleteQuadric(qobj); 
  349.     XCloseDisplay(dpy);
  350.     exit(0);
  351. }
  352.